#pragma once

#include "connection.hpp"
#include "common.hpp"
#include "reactor.hpp"
#include "calculator.hpp"

/*网络连接模块*/
class net_connection :public connection{
private:
    void Discard(size_t n){
        outbuffer.erase(0,n);
    }
public:
    net_connection(int fd,uint32_t event){
        setfd(fd);
        setevent(event);
        SetNonBlock(fd);
    }
    virtual void _recv()override{//读取链接的数据
        while(true)
        {
            char buffer[2048];
            int n=::recv(_sockfd,buffer,sizeof(buffer)-1,0);
            if(n>0){//成功读取了客户端的信息
                buffer[n]=0;
                inbuffer+=buffer;
            }
            else if(n==0){//客户端断开链接
                LOG(INFO)<<"client["<<_sockfd<<"] is quited";
                
                //删除该链接
                _own->erase(_sockfd);
                //关闭该链接
                Close();
                return;
            }
            else{//读取失败，进行处理
                if(errno==EAGAIN||errno==EWOULDBLOCK){
                    //所有的数据都读完了,开始处理数据
                    while(execute(inbuffer,outbuffer))
                        _send();
                    break;
                }
                else if(errno==EINTR){
                    //由于中断信号导致的读取失败
                    continue;
                }
                else{
                    //其他错误原因
                    LOG(ERROR)<<strerror(errno);
                    _except();
                }
            }
        }
  
    }

    virtual void _send()override{//向链接发送数据
        while(true){
            //将输出缓冲区中的数据发送出去
            ssize_t n=::send(_sockfd,outbuffer.c_str(),outbuffer.size(),0);
            if(n>0){//成功发送了n个字符
                //将输出缓冲区中的前n个字符删除
                Discard(n);
            }
            else if(n==0){//outbuff中已经没有数据了
                LOG(DEBUG)<<"all message sends";
                break;
            }
            else {//发送数据时发生以下错误
                if(errno==EAGAIN||errno==EWOULDBLOCK){//说明此时OS的输出缓冲区满了
                    //如果OS的输出缓冲区满了，就无法继续写入数据了。
                    //此时我们要等待OS将输出缓冲区中的数据发送，并且将其加入epoll中检测
                    _own->modifier(_sockfd,ADD_EVENT,EPOLLOUT);
                    return;
                }
                else if(errno==EINTR){
                    continue;
                }
                else{
                    _except();
                }
            }
        }
    }

    virtual void _except()override{//对于链接IO的异常处理
        //打印日志、关闭链接
        LOG(ERROR)<<"sockfd["<<_sockfd<<"]: "<<strerror(errno);
        _own->erase(_sockfd);
        Close();
    }

    ~net_connection(){}

};

connect_t make_NetConnection(int fd,uint32_t event){
    return std::make_shared<net_connection>(fd,event);
}